package com.king.common.utils.uuid;


import java.util.Random;

import com.king.common.utils.ip.Ipv4Util;

/**
 * Description:
 * 雪花算法获取分布式id
 * <p>
 * Twitter的Snowflake 算法 分布式系统中，有一些需要使用全局唯一ID的场景，有些时候我们希望能使用一种简单一些的ID，并且希望ID能够按照时间有序生成。
 * snowflake的结构如下(每部分用-分开):
 * 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
 * <p>
 * 第一位为未使用(符号位表示正数)，接下来的41位为毫秒级时间(41位的长度可以使用69年)
 * 然后是5位datacenterId和5位workerId(10位的长度最多支持部署1024个节点）
 * 最后12位是毫秒内的计数（12位的计数顺序号支持每个节点每毫秒产生4096个ID序号）
 *
 * @author Xander
 * datetime: 2021-03-16 15:22
 */
public class SnowFlakeUtil {

    /**
     * 雪花算法实例
     */
    private SnowFlake snowflake;

    private volatile static SnowFlakeUtil instance = null;

    public static SnowFlakeUtil getInstance() {
        if (instance == null) {
            synchronized (SnowFlakeUtil.class) {
                if (instance == null) {
                    instance = new SnowFlakeUtil();
                }
            }
        }
        return instance;
    }

    /**
     * 构造器中，通过IP段，设置 机器Id和数据中心id
     */
    private SnowFlakeUtil() {
        Random random = new Random();
        long workerId;//机器Id
        long datacenterId;//数据中心id
        String realIP = Ipv4Util.getInstance().getRealIP();
        if (realIP != null) {
            String[] strs = realIP.split("\\.");
            datacenterId = Integer.valueOf(strs[2]);
            workerId = Integer.valueOf(strs[3]);
        } else {
            //获取机器ip失败，则用随机数表示
            datacenterId = random.nextInt(256);
            workerId = random.nextInt(256);
        }
        //获取hutool工包中的雪花算法实例
        this.snowflake = new SnowFlake(datacenterId, workerId);
    }

    /**
     * 获取分布式id
     *
     * @return
     */
    public long nextId() {
        long id = this.snowflake.nextId();
        return id;
    }
}
